package com.github.bryx.workflow.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.bryx.workflow.command.*;
import com.github.bryx.workflow.command.executor.CommandExecutor;
import com.github.bryx.workflow.config.WorkflowInstanceAwareRegistry;
import com.github.bryx.workflow.domain.*;
import com.github.bryx.workflow.handler.WorkflowInstanceAware;
import com.github.bryx.workflow.service.WorkflowBuildTimeService;
import com.github.bryx.workflow.service.WorkflowRuntimeManager;
import com.github.bryx.workflow.service.WorkflowRuntimeQuery;
import com.github.bryx.workflow.service.WorkflowRuntimeService;
import com.github.bryx.workflow.util.StringUtil;
import com.github.bryx.workflow.util.WorkflowEngineUtil;
import com.google.common.base.Functions;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author jameswu
 * @Date 2021/6/10
 **/
@Service
@Slf4j
public class WorkflowRuntimeServiceImpl implements WorkflowRuntimeService {

    @Autowired
    WorkflowRuntimeQuery workflowRuntimeQuery;

    @Autowired
    WorkflowRuntimeManager workflowRuntimeManager;

    @Autowired
    WorkflowInstanceAwareRegistry workflowInstanceAwareRegistry;

    @Autowired
    WorkflowBuildTimeService buildTimeService;

    @Override
    public String start(String processKey, JSONObject formData, String executorId) {
        StartWorkflowInstanceCommand startWorkflowInstanceCommand = StartWorkflowInstanceCommand.builder()
                .processDefKey(processKey)
                .formData(formData)
                .executorId(executorId).build();
        return CommandExecutor.<String>execute(startWorkflowInstanceCommand);
    }

    @Override
    public String startAndAssign(String processKey, JSONObject formData, List<String> assignUserIds, List<String> assigneeGroupIds, String executorId) {
        StartWorkflowInstanceCommand startWorkflowInstanceCommand = StartWorkflowInstanceCommand.builder()
                .processDefKey(processKey)
                .formData(formData)
                .assignUserIds(assignUserIds)
                .assigneeGroupIds(assigneeGroupIds)
                .executorId(executorId).build();
        return CommandExecutor.<String>execute(startWorkflowInstanceCommand);
    }

    @Override
    public String startSubworkflow(String parentWorkflowTaskInstanceId, String processKey, JSONObject formData, String executorId, WorkflowInstanceRelation.Type workflowRelation) {
        StartWorkflowInstanceCommand startWorkflowInstanceCommand = StartWorkflowInstanceCommand.builder()
                .processDefKey(processKey)
                .formData(formData)
                .workflowInstanceRelation(workflowRelation)
                .parentWorkflowTaskInstanceId(parentWorkflowTaskInstanceId)
                .executorId(executorId).build();
        return CommandExecutor.<String>execute(startWorkflowInstanceCommand);
    }

    @Override
    public String startSubworkflowAndAssign(String parentWorkflowTaskInstanceId, String processKey, JSONObject formData, List<String> assignUserIds, List<String> assigneeGroupIds, String executorId, WorkflowInstanceRelation.Type workflowRelation) {
        StartWorkflowInstanceCommand startWorkflowInstanceCommand = StartWorkflowInstanceCommand.builder()
                .processDefKey(processKey)
                .formData(formData)
                .assignUserIds(assignUserIds)
                .assigneeGroupIds(assigneeGroupIds)
                .workflowInstanceRelation(workflowRelation)
                .parentWorkflowTaskInstanceId(parentWorkflowTaskInstanceId)
                .executorId(executorId).build();
        return CommandExecutor.<String>execute(startWorkflowInstanceCommand);
    }

    @Override
    public List<String> rejectBack(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, String executorId) {
        RejectBackUserTaskCommand command = RejectBackUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .build();
        return CommandExecutor.<List<String>>execute(command);
    }

    @Override
    public List<String> rejectBackAndAssign(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, List<String> assignUserIds, List<String> assigneeGroupIds, String executorId) {
        RejectBackUserTaskCommand command = RejectBackUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .assigneeUserIds(assignUserIds)
                .assigneeGroupIds(assigneeGroupIds)
                .build();
        return CommandExecutor.<List<String>>execute(command);
    }

    @Override
    public void claim(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, String executorId) {
        ClaimUserTaskCommand command = ClaimUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .build();
        CommandExecutor.<Void>execute(command);
    }

    @Override
    public void transfer(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, List<String> assignUserIds, List<String> assigneeGroupIds, String executorId) {
        TransferUserTaskCommand command = TransferUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .assigneeUserIds(assignUserIds)
                .assigneeGroupIds(assigneeGroupIds)
                .build();
        CommandExecutor.<Void>execute(command);
    }

    @Override
    public void modify(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, String executorId) {
        ModifyUserTaskCommand command = ModifyUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .build();
        CommandExecutor.<Void>execute(command);
    }

    @Override
    public List<String> submit(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, String executorId) {
        SubmitUserTaskCommand command = SubmitUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .build();
        return CommandExecutor.<List<String>>execute(command);
    }

    @Override
    public List<String> submitAndAssign(String workflowInstanceId, String workflowInstanceTaskId, JSONObject formData, List<String> assignUserIds, List<String> assigneeGroupIds, String executorId) {
        SubmitUserTaskCommand command = SubmitUserTaskCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .workflowTaskInstanceId(workflowInstanceTaskId)
                .executorId(executorId)
                .formData(formData)
                .assigneeUserIds(assignUserIds)
                .assigneeGroupIds(assigneeGroupIds)
                .build();
        return CommandExecutor.<List<String>>execute(command);
    }

    @Override
    public void close(String workflowInstanceId, String workflowInstanceTaskId, String executorId) {
        CloseWorkflowInstanceCommand command = CloseWorkflowInstanceCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .executorId(executorId)
                .build();
        CommandExecutor.<Void>execute(command);
    }

    @Override
    public void timerTriggered(WorkflowInstance workflowInstance, WorkflowTaskInstance workflowTaskInstance, WorkflowTimerInstance workflowTimerInstance, WorkflowTimerJob workflowTimerJob) {
        TimerTriggerCommand command = TimerTriggerCommand.builder()
                .workflowInstance(workflowInstance)
                .workflowTaskInstance(workflowTaskInstance)
                .workflowTimerInstance(workflowTimerInstance)
                .workflowTimerJob(workflowTimerJob)
                .build();
        CommandExecutor.<Void>execute(command);
    }

    /**
     *
     * 获取表单配置
     */
    @Override
    public Map<String, WorkflowDefProcessConfig.UserTaskConfig> userTaskConfig(String processKey, String workflowInstanceId, String userId) {
        FetchTaskConfigCommand command = FetchTaskConfigCommand.builder()
                .workflowInstanceId(workflowInstanceId)
                .processDefKey(processKey)
                .userId(userId)
                .build();
        return CommandExecutor.<Map<String, WorkflowDefProcessConfig.UserTaskConfig>>execute(command);
    }

    @Override
    public WorkflowRuntimeQuery query() {
        return workflowRuntimeQuery;
    }

    @Override
    public WorkflowRuntimeManager manager() {
        return workflowRuntimeManager;
    }
}
